package org.shaka.db.sqlbuilder.sql;

import java.util.List;

import org.shaka.db.sqlbuilder.component.Table.JoinInfo;
import org.shaka.db.sqlbuilder.component.Table.PairColumns;

public class SqlJoin {
    private final Type type;
    private final SqlAsPartial table;
    private SqlAsPartial linkTable;
    private SqlConditions conditions;

    private SqlJoin(Type type, SqlAsPartial table) {
        this.type = type;
        this.table = table;
    }

    public static SqlJoin left(SqlAsPartial table) {
        return new SqlJoin(Type.LEFT, table);
    }

    public static SqlJoin inner(SqlAsPartial table) {
        return new SqlJoin(Type.INNER, table);
    }

    public SqlJoin on(SqlAsPartial linkTable, SqlConditions conditions) {
        this.conditions = conditions;
        this.linkTable = linkTable;
        return this;
    }

    public SqlJoin on(SqlAsPartial linkTable) {
        return on(linkTable, null);
    }

    public SqlJoin on(SqlConditions conditions) {
        return on(null, conditions);
    }

    public void joinPartial(StringBuilder sb) {
        switch (type) {
        case INNER:
            sb.append(" INNER JOIN ");
            break;
        case LEFT:
            sb.append(" LEFT OUTER JOIN ");
            break;
        default:
            throw new RuntimeException(String.format("unknow join type [%s] ...", type));
        }
        sb.append(table.asPartial()).append(" ON ");
        if (linkTable != null && linkTable instanceof SqlTable && table instanceof SqlTable) {
            SqlTable t = (SqlTable) table;
            SqlTable l = (SqlTable) linkTable;
            JoinInfo info = t.getTable().getJoin(l.getTable());
            SqlConditions c = SqlConditions.and();
            if (info != null) {
                for (PairColumns pair : info.getPairColumns()) {
                    c.addCondition(t.column(pair.getSelfColumn()).equalTo(l.column(pair.getJoinColumn())));
                }
            }
            if (conditions != null) {
                c.addCondition(conditions);
            }
            c.conditionsPartial(sb);
        } else if (conditions != null) {
            conditions.conditionsPartial(sb);
        }
    }

    public boolean hasParams() {
        if (conditions == null)
            return false;
        return conditions.hasParams();
    }

    public List<Object> params() {
        return conditions.getParams();
    }

    public enum Type {
        INNER,
        LEFT
    }
}
